# -*- coding: utf-8 -*-

"""
Module implementing MainWindow.
"""
# 不断线的诀窍在于，先手动跑一次阻塞的测试，再使用多线程去跑，这样子就不会导致问题
from PyQt5.QtCore import pyqtSlot
from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import QMainWindow
from PyQt5.QtWidgets import QMessageBox
from PyQt5.QtGui import QIntValidator
from PyQt5.QtCore import QTimer
from ui_tool import *
from time import sleep
# 正则表达式，用于打印分割文本
import re
from socket import *
import sys
import struct
import datetime
import configparser

# 多线程
import os
from threading import Thread
################################################################################################################################################################################

import time #导入time模块
# 本地模块
import module.ControlCAN.ControlCAN as ControlCAN


# 剔除多余的0x、h、和空格
def get_hexstr_pure(hexstr):
    # 从0xaa bb ccH ddh eeff字符串转换为 aabbccddeeff 这样子的形式
    ## 仅仅保留 0~f 的字符
    hexstr = hexstr.replace("H", "h")
    hexstr = hexstr.replace("h", "")
    hexstr = hexstr.replace("X", "x")
    hexstr = hexstr.replace("0x", "")
    hexstr = hexstr.replace(" ", "")
    # fromhex 要求输入的字节长度是偶数
    if len(hexstr) % 2 != 0:
        hexstr = "0" + hexstr
    return hexstr

# 把值文本转换为hex文本
## 如果值是0x开头的，那么就转换为0x开头的hex 字符串（补齐为双数长度） 0xf --> 0x0f
## 如果值没有以0x开头，那么当成 int 型来处理 15 --> 0x0f
def value_string_to_hex_string(str_val):
    if str_val [0:2] != '0x':
        str_val = get_hexstr_pure(hex(int(str_val)))
    str_val = "0x" + get_hexstr_pure(str_val)
    return str_val

# 把hex string转字节
def hex_string_to_bytes(hex_str):
    byte_value = bytes.fromhex(get_hexstr_pure(hex_str)) # 将十六进制字符串转换为字节类型
    return byte_value

# 把hex string 转int
def hex_string_to_int(hex_str):
    byte_value = hex_string_to_bytes(hex_str) # 将十六进制字符串转换为字节类型
    int_val = int().from_bytes(byte_value, byteorder='big', signed=False)
    return int_val

# 把int string 转为8位hex列表
## 0, 1,2, 3,5 --> ['00', '01', '02', '03', '05']
def int_strings_to_hex_list(int_str, token = ","):
    int_str = int_str.replace(" ", "")
    int_str = int_str.replace("\t", "")
    int_str = int_str.replace("\n", "")

    retlist = list()
    for num in int_str.split(token):
        #print(num)
        int_val  = int(num)
        if int_val > 255:
            int_val = 255
        hex_str = ('{:02x}'.format(int_val))
        #print(hex_str)
        retlist.append(hex_str)
    #print(retlist)
    return retlist
#int_strings_to_hex_list("0,1,2,3, 5", ",")

def int_string_to_hex8(int_str):
    return '{:02x}'.format(int(int_str))
def int_string_to_hex16(int_str):
    return '{:04x}'.format(int(int_str))
def int_string_to_hex32(int_str):
    return '{:08x}'.format(int(int_str))

# 把hex string 补齐为8位
def hex_string_to_format_hex8(hex_str):
    # 限制长度在8以下，防止转换出错
    hex_str = get_hexstr_pure(hex_str)
    hex_str = hex_str[-2:]
    print(hex_str)
    int_val = hex_string_to_int(hex_str)
    hex_str = ('{:02x}'.format(int_val))
    return hex_str

# 把hex string 补齐为16位
def hex_string_to_format_hex16(hex_str):
    # 限制长度在16以下，防止转换出错
    hex_str = get_hexstr_pure(hex_str)
    hex_str = hex_str[-4:]
    int_val = hex_string_to_int(hex_str)
    hex_str = ('{:04x}'.format(int_val))
    return hex_str

# 把hex string 补齐为32位
def hex_string_to_format_hex32(hex_str):
    # 限制长度在32以下，防止转换出错
    hex_str = get_hexstr_pure(hex_str)
    hex_str = hex_str[-8:]
    int_val = hex_string_to_int(hex_str)
    hex_str = ('{:08x}'.format(int_val))
    return hex_str

# 把string按每length的长度切分为list
def split_string_by_length(string, length):
    return [string[i:i+length] for i in range(0, len(string), length)]

# 把hex string按2个字节一起，转换为short型数字并以文本的形式体现
def hexstr_form_to_short_str(hexstr):
    hexstr = get_hexstr_pure(hexstr)
    retstr = ''
    for item in split_string_by_length(hexstr, 4):
        item = item[2:4] + item[0:2]
        val = int.from_bytes(hex_string_to_bytes(item), byteorder='big', signed=False)
        retstr = retstr + str(val) + " "
    return retstr

# 把hexstr 按stride_cnt切分的 大端排序字符串
def hexstr_form_to_str_bigend(input_str, stride_cnt = 2, prefix = "0x",  suffix = " "):
    retstr = ''
    for item in split_string_by_length(input_str, stride_cnt):
        item = item[2:4] + item[0:2] # big endian
        #item = item[0:2] + item[2:4]# little endian
        retstr = retstr + prefix + item + suffix
    retstr = retstr.rstrip(suffix)
    return retstr

'''
bytes to hex string
eg:
b'\x01#Eg\x89\xab\xcd\xef\x01#Eg\x89\xab\xcd\xef'
'01 23 45 67 89 AB CD EF 01 23 45 67 89 AB CD EF'
'''
def bytes_to_hex_string(bs):
    hex_str = ''.join(['%02x ' % b for b in bs])
    return get_hexstr_pure(hex_str) #''.join(['%02X ' % b for b in bs])

# 把hex string们转int列表
def hex_strings_to_int_list(hex_str):
    hex_str = get_hexstr_pure(hex_str)
    hex_list = split_string_by_length(hex_str, 2)
    result = list()
    for hexstr in hex_list:
        result.append(hex_string_to_int(hexstr))
    print(result)
    return result


class MainWindow(QMainWindow, Ui_MainWindow):

    def closeEvent(self, event):
        #print("Quit without question")
        sys.exit(0)
        reply = QMessageBox.question(self, '提示',
                        "确认退出吗",
                        QMessageBox.Yes | QMessageBox.No,
                        QMessageBox.No)
        if reply == QMessageBox.Yes:
            if self.myserial1.isOpen() == True:
                # 停止发送定时器
                self.myserial1.close()
                return
            try:
                self.udpClient.close()
            except :
                pass
            #关闭CAN
            canDLL.VCI_CloseDevice(VCI_USBCAN2, 0) 
            event.accept()
            sys.exit(0)   # 退出程序
        else:
            event.ignore()

    def ui_doRecvCanFrame(self, chn_str = "ch0"):
        recvCnt = 1
        timeout_ms = 2000
        result = self.myCan.recvFrame(chn_str, recvCnt, timeout_ms)
        if len(result) == 0:
            print('接收失败')
            #return False
        for can_obj in result:
            print('接收成功')
            print('ID：')
            print(can_obj.ID)
            print('DataLen：')
            print(can_obj.DataLen)
            print('Data：')
            print(list(can_obj.Data))

    @pyqtSlot()
    def on_button_recv_can_frame_from_ch0_clicked(self) :
        self.ui_doRecvCanFrame("ch0")
    @pyqtSlot()
    def on_button_recv_can_frame_from_ch1_clicked(self) :
        self.ui_doRecvCanFrame("ch1")


    def ui_doSendCanFrame(self, chn_str = "ch0"):
        data_hexstr = ""
        data_list = hex_strings_to_int_list(self.lineEdit_data_frame.text())
        for data_int in data_list:
            data_hexstr = data_hexstr + int_string_to_hex8(str(data_int)) + " "
        self.lineEdit_data_frame.setText(data_hexstr)

        frame_format_str = "std"
        if self.checkBox_std_frame.isChecked():
            frame_format_str = "std"
        else:
            frame_format_str = "ext"

        frame_type_str = "data"
        if self.checkBox_data_frame.isChecked():
            frame_type_str = "data"
        else:
            frame_type_str = "ext"
        frameID = self.myCan.toSafeFrameID(self.lineEdit_frame_id.text(), frame_format_str)
        self.lineEdit_frame_id.setText(frameID)

        self.myCan.sendFrame(frameID, data_hexstr, chn_str , frame_format_str, frame_type_str)

    @pyqtSlot()
    def on_button_send_can_frame_to_ch0_clicked(self) :
        self.ui_doSendCanFrame("chn0")
    @pyqtSlot()
    def on_button_send_can_frame_to_ch1_clicked(self) :
        self.ui_doSendCanFrame("chn1")

    @pyqtSlot()
    def on_buttom_open_can_clicked(self):
        if self.buttom_open_can.text() == "打开CAN" :
            ret = self.myCan.openCan(self.comboBox_ch0_brate.currentText(), self.comboBox_ch1_brate.currentText())
            if ret == -1:
                QMessageBox.critical(self, 'CAN', 'CAN初始化失败，请检查CAN')
                self.myCan.closeCan()
            else:
                self.buttom_open_can.setText("关闭CAN")
                self.can_opened = True
        elif self.buttom_open_can.text() == "关闭CAN" :
            self.myCan.closeCan()
            self.buttom_open_can.setText("打开CAN")
            self.can_opened = False
        self.comboBox_ch0_brate.setEnabled(not self.can_opened)
        self.comboBox_ch1_brate.setEnabled(not self.can_opened)

    @pyqtSlot()
    def on_checkBox_std_frame_clicked(self) :
        self.checkBox_ext_frame.setChecked(not self.checkBox_std_frame.isChecked())
    @pyqtSlot()
    def on_checkBox_ext_frame_clicked(self) :
        self.checkBox_std_frame.setChecked(not self.checkBox_ext_frame.isChecked())
    @pyqtSlot()
    def on_checkBox_data_frame_clicked(self) :
        self.checkBox_remote_frame.setChecked(not self.checkBox_data_frame.isChecked())
    @pyqtSlot()
    def on_checkBox_remote_frame_clicked(self) :
        self.checkBox_data_frame.setChecked(not self.checkBox_remote_frame.isChecked())

    #@pyqtSlot()
    def comboBox_ch0_brate_selectionchange(self,i):
        self.comboBox_ch1_brate.setCurrentIndex(i)
    ##@pyqtSlot()
    #def comboBox_ch1_brate_selectionchange(self,i):
    #    self.comboBox_ch0_brate.setCurrentIndex(i)

    def refresh_can_bitrate_comboBox(self, comboBox):
        plist = ["20k","40k", "50k", "80k", "100k", "125k", "200k", "250k", "400k", "500k", "666k", "800k", "1000k", "33.33k", "66.66k", "83.33l"]

        # 把所有的可用的串口输出到comboBox中去
        comboBox.clear()
        for i in plist:
            comboBox.addItem(i)

    def __init__(self, parent=None):

        super(MainWindow, self).__init__(parent)
        self.myCan = ControlCAN.ControlCAN()
        self.setupUi(self)
        self.can_opened = False
        
        #self.testThread = thread_for_test()
        #设置任务线程发射信号触发的函数
        #self.testThread.signal_after_test.connect(self.slot_for_after_test)
        #self.testThread.signal_before_test.connect(self.slot_for_before_test)
        #self.testThread.signal_for_update_log_ui.connect(self.slot_for_update_ui)
        #self.testThread.ui = self
        #self.refresh_serial_list()

        self.refresh_can_bitrate_comboBox(self.comboBox_ch0_brate)
        self.refresh_can_bitrate_comboBox(self.comboBox_ch1_brate)
        self.comboBox_ch0_brate.currentIndexChanged.connect(self.comboBox_ch0_brate_selectionchange)
        #self.comboBox_ch1_brate.currentIndexChanged.connect(self.comboBox_ch1_brate_selectionchange)

        # 实例化一个定时器
        #self.timer = QTimer(self)

        # 定时器调用读取串口接收数据
        #self.timer.timeout.connect(self.check_is_dev_online_and_uipdate_ui)
        #self.echo_log_as_info("启动测试软件")
        #self.timer_restart(1000)
        #self.gen_report()
        #self.testThread.start()

if __name__ == "__main__":

    app = QtWidgets.QApplication(sys.argv)

    ui = MainWindow()
    ui.show()

    sys.exit(app.exec_())



